package cn.ddiancan.auth.service.repository;

import java.util.List;
import java.util.Objects;

import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.PreparedStatementSetter;
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.util.CollectionUtils;

@Slf4j
public class XddJdbcOAuth2AuthorizationService extends JdbcOAuth2AuthorizationService {

    // @formatter:off
    private static final String COLUMN_NAMES = "id, "
        + "registered_client_id, "
        + "principal_name, "
        + "authorization_grant_type, "
        + "authorized_scopes, "
        + "attributes, "
        + "state, "
        + "authorization_code_value, "
        + "authorization_code_issued_at, "
        + "authorization_code_expires_at,"
        + "authorization_code_metadata,"
        + "access_token_value,"
        + "access_token_issued_at,"
        + "access_token_expires_at,"
        + "access_token_metadata,"
        + "access_token_type,"
        + "access_token_scopes,"
        + "oidc_id_token_value,"
        + "oidc_id_token_issued_at,"
        + "oidc_id_token_expires_at,"
        + "oidc_id_token_metadata,"
        + "refresh_token_value,"
        + "refresh_token_issued_at,"
        + "refresh_token_expires_at,"
        + "refresh_token_metadata,"
        + "user_code_value,"
        + "user_code_issued_at,"
        + "user_code_expires_at,"
        + "user_code_metadata,"
        + "device_code_value,"
        + "device_code_issued_at,"
        + "device_code_expires_at,"
        + "device_code_metadata";
    // @formatter:on

    private static final String TABLE_NAME = "oauth2_authorization";

    private static final String CLIENT_ID_FILTER = "registered_client_id = ? and principal_name = ?";

    // @formatter:off
    private static final String LOAD_AUTHORIZATION_SQL = "SELECT " + COLUMN_NAMES
        + " FROM " + TABLE_NAME
        + " WHERE ";
    // @formatter:on

    public XddJdbcOAuth2AuthorizationService(JdbcOperations jdbcOperations,
        RegisteredClientRepository registeredClientRepository) {
        super(jdbcOperations, registeredClientRepository);

    }

    @Override
    public void save(OAuth2Authorization authorization) {
        // OAuth2Authorization oAuth2Authorization =
        //     findByClientId(authorization.getRegisteredClientId(), authorization.getPrincipalName());
        // if (Objects.nonNull(oAuth2Authorization)) {
        //     authorization = OAuth2Authorization.from(authorization).id(oAuth2Authorization.getId()).build();
        // }
        super.save(authorization);
    }

    public OAuth2Authorization findByClientId(String clientId, String pricipalName) {
        return findBy(CLIENT_ID_FILTER, clientId, pricipalName);
    }

    private OAuth2Authorization findBy(String filter, String clientId, String principalName) {
        try {
            PreparedStatementSetter pss = (preparedStatement) -> {
                preparedStatement.setString(1, clientId);
                preparedStatement.setString(2, principalName);
            };
            List<OAuth2Authorization> result =
                getJdbcOperations().query(LOAD_AUTHORIZATION_SQL + filter, pss, getAuthorizationRowMapper());
            return CollectionUtils.isEmpty(result) ? null : result.get(0);
        } catch (DataAccessException e) {
            log.error("Error occurred while finding authorization", e);
        }
        return null;
    }
}
